﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Reflection;
using System.Linq.Expressions;

namespace DAL
{
    public partial class AuditRecord
    {


        //public AuditAction Action { get; set; }

        //public object Entity { get; set; }
        public LambdaExpression KeySelector { get; set; }

        //public string EntityTable { get; set; }
        //public int EntityTableKey { get; set; }

        //public string AssociationTable { get; set; }
        //public int? AssociationTableKey { get; set; }


        private readonly List<ModifiedEntityProperty> _properties = new List<ModifiedEntityProperty>();
        public IList<ModifiedEntityProperty> ModifiedProperties { get { return _properties; } }

        public int add(dbGestionDataContext _db,
                        AuditAction action,
                        int idUsuarioMod,
                        int idInternal,
                        Object entity)
        {


            this.Action = (byte)action;
            this.AuditDate = DateTime.Now;
            this.EntityTable = entity.GetType().Name;
            this.EntityTableKey = idInternal;
            this.UserName = _db.Empleados.Single(p=>p.idInternal==idUsuarioMod).descripcion;
            

            Type entityType = entity.GetType();
            IAuditPropertyResolver resolver = AuditPropertyResolver.GetResolver(entityType);

            if (action == AuditAction.Update)
            {
                var mmi = this.GetModifiedMembers(_db,entity);

                foreach (MemberAudit mi in mmi)
                {
                    ModifiedEntityProperty values = resolver.GetAuditValue(mi.Member, mi.OriginalValue, mi.CurrentValue);
                    if (values != null)
                    {
                        AuditRecordField field = new AuditRecordField();
                        field.MemberName = values.MemberName;
                        field.OldValue = values.OldValue.ToString();
                        field.NewVale = values.NewValue.ToString();
                         this.AuditRecordField.Add(field);
                    }
                }
            }
            else if (action == AuditAction.Insert)
            {
                PropertyInfo[] props = entity.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
                foreach (PropertyInfo pi in props)
                {
                    ModifiedEntityProperty values = resolver.GetAuditValue(pi, null, pi.GetValue(entity, null));
                    if (values != null)
                    {
                        AuditRecordField field = new AuditRecordField();
                        field.MemberName = values.MemberName;
                        field.OldValue = values.OldValue.ToString();
                        field.NewVale = values.NewValue.ToString();
                        this.AuditRecordField.Add(field);
                    }
                }
            }
            else
            {
                PropertyInfo[] props = entity.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
                foreach (PropertyInfo pi in props)
                {
                    ModifiedEntityProperty values = resolver.GetAuditValue(pi, pi.GetValue(entity, null), null);
                    if (values != null)
                    {
                        AuditRecordField field = new AuditRecordField();
                        field.MemberName = values.MemberName;
                        field.OldValue = values.OldValue.ToString();
                        field.NewVale = values.NewValue.ToString();
                        this.AuditRecordField.Add(field);
                    }
                }
            }



            //// valores anteriores
            //AuditRecord audit = new AuditRecord();

            //        audit.Action = accion;
            //        audit.AuditDate = DateTime.Now;
            //        audit.EntityTable = objecto.GetType().Name;
            //        audit.EntityTableKey = idInternal;
            //        audit.UserName = _db.Empleados.Single(p=>p.idInternal==idUsuarioMod).descripcion;
            

            //IEnumerable<MemberAudit> list = this.GetModifiedMembers(_db,objecto);

            //foreach (MemberAudit av in list)
            //{
            //    // validar si el atributo esta enlazado a otra tabla.

            //    AuditRecordField field = new AuditRecordField();
            //    field.MemberName = av.Member.Name;
            //    field.OldValue = av.OriginalValue.ToString();
            //    field.NewVale = av.CurrentValue.ToString();
            //    audit.AuditRecordField.Add(field);
            //}

            _db.AuditRecord.InsertOnSubmit(this);
            _db.SubmitChanges();
            return this.Id;

        }


        public void update(dbGestionDataContext _db,
                            Object entity,
            AuditAction action)
        {



            Type entityType = entity.GetType();
            IAuditPropertyResolver resolver = AuditPropertyResolver.GetResolver(entityType);

            if (action == AuditAction.Update)
            {
                var mmi = this.GetModifiedMembers(_db, entity);

                foreach (MemberAudit mi in mmi)
                {
                    ModifiedEntityProperty values = resolver.GetAuditValue(mi.Member, mi.OriginalValue, mi.CurrentValue);
                    if (values != null)
                    {
                        AuditRecordField field = new AuditRecordField();
                        field.MemberName = values.MemberName;
                        field.OldValue = values.OldValue.ToString();
                        field.NewVale = values.NewValue.ToString();
                        this.AuditRecordField.Add(field);
                    }
                }
            }
            else if (action == AuditAction.Insert)
            {
                PropertyInfo[] props = entity.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
                foreach (PropertyInfo pi in props)
                {
                    ModifiedEntityProperty values = resolver.GetAuditValue(pi, null, pi.GetValue(entity, null));
                    if (values != null)
                    {
                        AuditRecordField field = new AuditRecordField();
                        field.MemberName = values.MemberName;
                        field.OldValue = values.OldValue.ToString();
                        field.NewVale = values.NewValue.ToString();
                        this.AuditRecordField.Add(field);
                    }
                }
            }
            else
            {
                PropertyInfo[] props = entity.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
                foreach (PropertyInfo pi in props)
                {
                    ModifiedEntityProperty values = resolver.GetAuditValue(pi, pi.GetValue(entity, null), null);
                    if (values != null)
                    {
                        AuditRecordField field = new AuditRecordField();
                        field.MemberName = values.MemberName;
                        field.OldValue = values.OldValue.ToString();
                        field.NewVale = values.NewValue.ToString();
                        this.AuditRecordField.Add(field);
                    }
                }
            }





            //IEnumerable<MemberAudit> list = this.GetModifiedMembers(_db, objecto);

            //foreach (MemberAudit av in list)
            //{
            //    // validar si el atributo esta enlazado a otra tabla.

            //    AuditRecordField field = new AuditRecordField();
            //    field.MemberName = av.Member.Name;
            //    field.OldValue = av.OriginalValue.ToString();
            //    field.NewVale = av.CurrentValue.ToString();
            //    this.AuditRecordField.Add(field);
            //}

            ////_db.AuditRecord.InsertOnSubmit(audit);
            _db.SubmitChanges();
            

        }





        public IEnumerable<MemberAudit> GetModifiedMembers(dbGestionDataContext _db, object entity)
        {
            ITable table = _db.GetTable(entity.GetType());
            return
                table.GetModifiedMembers(entity).Select(
                    mmi =>
                    new MemberAudit
                    {
                        Member = mmi.Member,
                        CurrentValue = mmi.CurrentValue,
                        OriginalValue = mmi.OriginalValue
                    });
        }





    



    }
}
